home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / The World of Computer Software.iso / ccr.zip / CCR-STD.T < prev    next >
Text File  |  1993-01-23  |  19KB  |  681 lines

  1. /*
  2.  * Colossal Cave Revisited
  3.  *
  4.  * A remake of Willie Crowther and Don Woods' classic Adventure.
  5.  * Converted from Donald Ekman's PC port of the original FORTRAN source.
  6.  * TADS version by David M. Baggett for ADVENTIONS.
  7.  *
  8.  * Please document all changes in the history so we know who did what.
  9.  *
  10.  * This source code is copylefted under the terms of the GNU Public
  11.  * License.  Essentially, this means that you are free to do whatever
  12.  * you wish with this source code, provided you do not charge any
  13.  * money for it or for any derivative works.
  14.  *
  15.  * ADVENTIONS distributes this game, but you are free to do what you will
  16.  * with it, provided you adhere to the terms in the GNU Public License.
  17.  * Send correspondence regarding this game or original works distributed
  18.  * by ADVENTIONS to 
  19.  *
  20.  *    ADVENTIONS
  21.  *    PO Box 851
  22.  *    Columbia, MD 21044
  23.  *
  24.  * If you would like a catalog of releases, please enclose a SASE.  Thanks!
  25.  *
  26.  * Contributors
  27.  *
  28.  *    dmb    In real life:    David M. Baggett
  29.  *        Internet:    <dmb@ai.mit.edu>
  30.  *        Compu$erve:    76440,2671 (ADVENTIONS account)
  31.  *        GEnie:        ADVENTIONS
  32.  *
  33.  * Modification History
  34.  *
  35.  * 1-Jan-93    dmb    rec.arts.int-fiction BETA release (source only)
  36.  *                      For beta testing only -- not for general
  37.  *            distribution.
  38.  *
  39.  */
  40.  
  41. /*
  42.  * This file includes the typical standard definitions.
  43.  */
  44. check_for_closing: function;
  45. check_for_endgame: function;
  46. makend: function;
  47.  
  48. /*
  49.  * This is the program's entry point.
  50.  */
  51. init: function
  52. {
  53.     local l;
  54.  
  55.     "\b\b\b\b";
  56.     version.sdesc;    // display the game's name and version number
  57.     "\b";
  58.  
  59.     //
  60.     // See if the player wants an easy or normal game.  (This
  61.     // was the "Do you want instructions?" query in the original.)
  62.     // In novice mode the lamp batteries last longer.
  63.     //
  64.     // It might also make sense to make some other things easier, like
  65.     // the number of dwarves or their tenacity, but for now we only make
  66.     // the change that was made for the original's novice mode.
  67.     //
  68.     // Novice mode costs the player global.novicepoints.
  69.     //
  70.     "Shall I go easy on you this game?  (An easy game will cost you ";
  71.     say(-1 * global.novicepoints); " points.)\n>";
  72.     if (yorn()) {
  73.         incscore(global.novicepoints);
  74.  
  75.         //
  76.         // Change some stuff to make the game easier.
  77.         //
  78.         brass_lantern.turnsleft := 1000;
  79.     }
  80.  
  81.     "\b";
  82.  
  83.     //
  84.     // Randomize after the first turn.  (This allows us to make a verb
  85.     // that prevents randomization for regression testing.)
  86.     //
  87.     setfuse(makend, 1, nil);
  88.     
  89.     setdaemon(turncount, nil);        // start turn counter daemon
  90.     setdaemon(check_for_closing, nil);    // start cave closing daemon
  91.     setdaemon(check_for_endgame, nil);    // start endgame daemon
  92.     Me.location := At_End_Of_Road;        // move player -> 1st location
  93.     Me.location.lookAround(true);        // show player where he is
  94.  
  95.     //
  96.     // Initialize non-player characters (dwarves, pirate) if we're
  97.     // in debug mode.  Otherwise do it from preinit.
  98.     //
  99.     if (global.debug)
  100.         initNPC();
  101.  
  102.     //
  103.     // Check room connections for integrity.
  104.     //
  105.     check_connections();
  106. }
  107. makend: function(parm)
  108. {
  109.     if (global.nondeterministic) {
  110.         randomize();
  111.     }
  112.     else {
  113.         "\b*** This will be a deterministic game. ***";
  114.     }
  115.  
  116.     //
  117.     // Once we've randomized (if we're going to at all), place
  118.     // all the NPC's.
  119.     //
  120.     Dwarves.place;
  121.     notify(Dwarves, &move, 0);
  122.  
  123.     Pirates.place;
  124.     notify(Pirates, &move, 0);
  125. }
  126.  
  127. /*
  128.  * The following function is run at compile time to build lists and
  129.  * do other compute-intensive things ahead of time.
  130.  */
  131. preinit: function
  132. {
  133.     local o;
  134.  
  135.     //
  136.     // Construct list of light sources
  137.     //
  138.     global.lamplist := [];
  139.     o := firstobj(lightsource);
  140.     while (o <> nil) {
  141.         global.lamplist := global.lamplist + o;
  142.         o := nextobj(o, lightsource);
  143.     }
  144.  
  145.     //
  146.     // Count treasures to get initial number of treasures
  147.     // left to find.
  148.     //
  149.     global.treasures := 0;
  150.     o := firstobj(CCR_treasure_item);
  151.     while (o <> nil) {
  152.         global.treasurelist := global.treasurelist + o;
  153.         global.treasures := global.treasures + 1;
  154.  
  155.         o := nextobj(o, CCR_treasure_item);
  156.     }
  157.  
  158.     //
  159.     // Initialize non-player characters (dwarves, pirate) from
  160.     // here if we're not in debug mode.  Otherwise do it in init.
  161.     //
  162.     if (not global.debug)
  163.         initNPC();
  164. }
  165.  
  166. die: function
  167. {
  168.     local    resurrect;
  169.  
  170.     P(); I();
  171.  
  172.     // DMB: "reincarnate" in the text below should actually
  173.     // be "resurrect," since presumably you're coming back
  174.     // as the same person you were before.  I have left the
  175.     // original text as is, however, for the sake of purity.
  176.  
  177.     resurrect := nil;    // assume no resurrection
  178.  
  179.     if (global.closed) {
  180.         "It looks as though you're dead.  Well, seeing as how 
  181.         it's so close to closing time anyway, I think we'll 
  182.         just call it a day.";
  183.  
  184.         call_it_a_day();
  185.     }
  186.     else if (global.deaths = 0) {
  187.         "Oh dear, you seem to have gotten yourself killed.  I 
  188.         might be able to help you out, but I've never really 
  189.         done this before.  Do you want me to try to 
  190.         reincarnate you?\b>";
  191.  
  192.         if (yorn()) {
  193.             "\bAll right.  But don't blame me if something 
  194.             goes wr...... \b \ \ \ \ \ \ \ \ \ \ \ \ \ \ 
  195.             \ \ \ \ \ \ --- POOF!! --- \bYou are engulfed 
  196.             in a cloud of orange smoke.  Coughing and 
  197.             gasping, you emerge from the smoke and 
  198.             find that you're....";
  199.  
  200.             resurrect := true;
  201.         }
  202.         else
  203.             "\bVery well.";
  204.     }
  205.     else if (global.deaths = 1) {
  206.         "You clumsy oaf, you've done it again!  I don't know 
  207.         how long I can keep this up.  Do you want me to try 
  208.         reincarnating you again?\b>";
  209.  
  210.         if (yorn()) {
  211.             "\bOkay, now where did I put my orange 
  212.             smoke?....  >POOF!<\bEverything disappears in 
  213.             a dense cloud of orange smoke.";
  214.  
  215.             resurrect := true;
  216.         }
  217.         else
  218.             "\bProbably a wise choice.";
  219.     }
  220.     else if (global.deaths = 2) {
  221.         "Now you've really done it!  I'm out of orange smoke! 
  222.         You don't expect me to do a decent reincarnation 
  223.         without any orange smoke, do you?\b>";
  224.  
  225.         if (yorn()) {
  226.             "\bOkay, if you're so smart, do it yourself!  
  227.             I'm leaving!";
  228.         }
  229.         else
  230.             "\bI thought not!";
  231.     }
  232.  
  233.     global.deaths := global.deaths + 1;
  234.     incscore(global.deathpoints);
  235.  
  236.     if (resurrect) {
  237.         //
  238.         // Resurrection:
  239.         //
  240.         // 1) Drop all player's items where he was killed.
  241.         // 2) Move lamp outside of building and turn it off.
  242.         // 3) Move the player into the building.
  243.         //
  244.         while (length(Me.contents) > 0)
  245.             Me.contents[1].moveInto(Me.location);
  246.         brass_lantern.turnoff;
  247.         brass_lantern.moveInto(At_End_Of_Road);
  248.  
  249.         "\b";
  250.         Me.travelTo(Inside_Building);
  251.     }
  252.     else {
  253.         //
  254.         // Player's done for good -- show score and quit.
  255.         //
  256.         scoreRank();
  257.         terminate();
  258.         quit();
  259.         abort;
  260.     }
  261. }
  262.  
  263. /*
  264.  * The player loses without any chance of reincarnation (for example,
  265.  * if his batteries run out.)
  266.  */
  267. call_it_a_day: function
  268. {
  269.     scoreRank();
  270.     terminate();
  271.     quit();
  272.     abort;
  273. }
  274.  
  275. /*
  276.  * The player has finished the game on a positive note.
  277.  */
  278. win: function
  279. {
  280.     scoreRank();
  281.     terminate();
  282.     quit();
  283.     abort;
  284. }
  285.  
  286. /*
  287.  * Show score and ranking
  288.  */
  289. scoreRank: function
  290. {
  291.     local    pn;
  292.  
  293.     "You have scored "; say(global.score); " out of a possible ";
  294.     say(global.maxscore); ", using "; say(global.turnsofar);
  295.     if (global.turnsofar = 1)
  296.         " turn.";
  297.     else
  298.         " turns.";
  299.  
  300.     "\n";
  301.         
  302.     if (global.score < 35) {
  303.         //
  304.         // DMB: This originally said, "Better luck next time,"
  305.         // but this isn't really appropriate anymore since
  306.         // we now give the player his ranking when he types
  307.         // \"score.\"  (In the original, you only got your
  308.         // rank when the game was over.)
  309.         //
  310.         "You are obviously a rank amateur.";
  311.         pn := 35 - global.score;
  312.     }
  313.     else if (global.score < 100) {
  314.         "Your score qualifies you as a Novice Class adventurer.";
  315.         pn := 100 - global.score;
  316.     }
  317.     else if (global.score < 130) {
  318.         "You have achieved the rating: \"Experienced Adventurer\".";
  319.         pn := 130 - global.score;
  320.     }
  321.     else if (global.score < 200) {
  322.         "You may now consider yourself a \"Seasoned Adventurer\".";
  323.         pn := 200 - global.score;
  324.     }
  325.     else if (global.score < 250) {
  326.         "You have reached \"Junior Master\" status.";
  327.         pn := 250 - global.score;
  328.     }
  329.     else if (global.score < 300) {
  330.         "Your score puts you in Master Adventurer Class C.";
  331.         pn := 300 - global.score;
  332.     }
  333.     else if (global.score < 330) {
  334.         "Your score puts you in Master Adventurer Class B.";
  335.         pn := 330 - global.score;
  336.     }
  337.     else if (global.score < 349) {
  338.         "Your score puts you in Master Adventurer Class A.";
  339.         pn := 349 - global.score;
  340.     }
  341.     else {
  342.         "All of Adventuredom gives tribute to you, Adventurer
  343.         Grandmaster!";
  344.  
  345.         pn := 0;
  346.     }
  347.  
  348.     "\n";
  349.  
  350.     if (pn > 0) {
  351.         "To achieve the next higher rating, you need ";
  352.         say(pn); " more ";
  353.  
  354.         if (pn = 1)
  355.             "point.";
  356.         else
  357.             "points.";
  358.     }
  359.     else
  360.         "To achieve the next higher rating would be a neat trick!";
  361.     
  362.     "\n";
  363. }
  364.  
  365. /*
  366.  * Print a nice message when we exit.
  367.  */
  368. terminate: function
  369. {
  370.     "\b";
  371.     "Come back and visit the newly remodelled Colossal Cave soon!";
  372. }
  373.  
  374. /*
  375.  * What we say when the user enters a blank line.
  376.  */
  377. pardon: function
  378. {
  379.     "What?";
  380. }
  381.  
  382. /*
  383.  *   The numObj object is used to convey a number to the game whenever
  384.  *   the player uses a number in his command.  For example, "turn dial
  385.  *   to 621" results in an indirect object of numObj, with its "value"
  386.  *   property set to 621.
  387.  */
  388. numObj: basicNumObj;  // use default definition from adv.t
  389.  
  390. /*
  391.  *   strObj works like numObj, but for strings.  So, a player command of
  392.  *     type "hello" on the keyboard
  393.  *   will result in a direct object of strObj, with its "value" property
  394.  *   set to the string 'hello'.
  395.  *
  396.  *   Note that, because a string direct object is used in the save, restore,
  397.  *   and script commands, this object must handle those commands.
  398.  */
  399. strObj: basicStrObj;     // use default definition from adv.t
  400.  
  401. /*
  402.  *   The "global" object is the dumping ground for any data items that
  403.  *   don't fit very well into any other objects.  The properties of this
  404.  *   object that are particularly important to the objects and functions
  405.  *   are defined here; if you replace this object, but keep other parts
  406.  *   of this file, be sure to include the properties defined here.
  407.  */
  408. global: object
  409.     //
  410.     // Scoring values
  411.     // Points for treasures are kept in the treasures themselves.
  412.     //
  413.     score = 36        // start out with 36 points:
  414.                 // (2 + (-1 * quitpoints) +
  415.                 // (-1 * deathpoints) * 3)
  416.     maxscore = 350        // maximum possible score
  417.     novicepoints = -5    // points for playing in easy mode (neg.)
  418.     quitpoints = -4        // points for quitting (neg.)
  419.     deathpoints = -10    // points gained each time player dies (neg.)
  420.     farinpoints = 25    // points for getting well into the cave
  421.     wittpoints = 1        // points for reaching Witt's End
  422.     closingpoints = 25    // points for surviving until cave closing time
  423.     endpoints = 10        // points for getting to final puzzle
  424.     almostpoints = 20    // points for *almost* getting final puzzle
  425.     winpoints = 35        // points for winning the final puzzle
  426.  
  427.     treasures = 0        // treasures left to deposit;
  428.                 // filled in by preinit
  429.     treasurelist = []    // list of all treasures in the game;
  430.                 // filled in by preinit
  431.  
  432.     //
  433.     // NPC stuff
  434.     //
  435.     dwarves = 5        // number of dwarves wandering about the cave
  436.                 // (Was 5 in original.)
  437.     pirates = 1        // number of pirates lurking in the cave
  438.                 // (Was 1 in original.)
  439.  
  440.     dtenacity = 96        // percentage chance that a dwarf will
  441.                 // follow the player if in an adjacent
  442.                 // location.  (Was 100 in original.)
  443.     ptenacity = 50        // percentage chance that a pirate will
  444.                 // follow the player if in an adjacent
  445.                 // location.  Don't set this too high or
  446.                 // the game will get really bogus!
  447.  
  448.     //
  449.     // Where to start dwarves and pirate(s) out.  Dwarves are placed
  450.     // in the locations given by drawfloc; if no locations remain when
  451.     // we're placing a dwarf, we just put him in a random room selected
  452.     // from NPCrooms.
  453.     //
  454.     // Note that the player gets the axe from the dwarf, so it's
  455.     // fairly important to put at least dwarf early on (but only
  456.     // in a room that's not off limits to NPC's!)
  457.     //
  458.     // Ditto for pirate(s).
  459.     //
  460.     dwarfloc = [
  461.         In_Hall_Of_Mists
  462.     ]
  463.     pirateloc = []
  464.  
  465.     dwarfattack = 75    // percentage chance that a dwarf will
  466.                 // throw a knife at the player if he's
  467.                 // in the same location.  (Was 100 in
  468.                 // the original.)
  469.     dwarfhit = 66        // percentage chance the player will
  470.                 // hit a dwarf with his axe
  471.                 // (Was 1 in 3 chance in the original.)
  472.     dwarfaccuracy = 9    // percentage chance that a dwarf will
  473.                 // hit the player with a thrown knife
  474.                 // (Was 9.5 in the original.)
  475.  
  476.     //
  477.     // Output formatting
  478.     //
  479.     verbose = nil        // we are currently in TERSE mode
  480.     indent = true        // indent paragraph beginnings
  481.     doublespace = true    // double space the text
  482.  
  483.     //
  484.     // Other stuff
  485.     //
  486.     deaths = 0        // number of times the player has died
  487.     closingtime = 30    // close this many turns after player takes
  488.                 // the last treasure.  (was 30 in original)
  489.     bonustime = 20        // start endgame this many turns after
  490.                 // the cave closes.  In the original this
  491.                 // was 50, but since we've change things
  492.                 // slightly (the closing timer starts once
  493.                 // the player deposits the last treasure in
  494.                 // the building, not once he merely *sees*
  495.                 // it), we've had to make this value smaller.
  496.                 // If we were to leave it the way it was,
  497.                 // it would be very hard to finish the game
  498.                 // before the lamp batteries died.
  499.     panictime = 15        // extend timer by this many turns when player
  500.                 // panics at closing time
  501.  
  502.     closed = nil        // is the cave closed yet?
  503.  
  504.     turnsofar = 0        // no turns have transpired so far 
  505.     lamplist = []        // list of all known light providers
  506.                 // in the game
  507.     NPCrooms = []        // list of rooms NPC's (dwarves, pirate)
  508.                 // can go to
  509.  
  510.     //
  511.     // Special wizard stuff.  Don't mess with it!
  512.     //
  513.     nondeterministic = true    // default to nondeterministic game
  514.     debug = nil        // debugging messages on/off
  515. ;
  516.  
  517. /*
  518.  *   The "version" object defines, via its "sdesc" property, the name and
  519.  *   version number of the game.  Change this to a suitable name for your
  520.  *   game.
  521.  */
  522. version: object
  523.     sdesc = {
  524.         "Colossal Cave Revisited\n
  525.         Version 0.9, released January 1993.\b";
  526.  
  527.         "A remake of Willie Crowther and Don Woods' classic
  528.         Adventure.\n Converted from Donald Ekman's PC port of 
  529.         the original FORTRAN source.\n TADS version by David 
  530.         M.\ Baggett for ADVENTIONS.\b";
  531.  
  532.         "Colossal Cave Revisited and its accompanying source 
  533.         code are\n Copyright (C) 1993 David M.\ Baggett."; P();
  534.  
  535.         I(); "This program is free software; you can 
  536.         redistribute it and/or modify it under the terms of 
  537.         version 2 of the GNU General Public License as 
  538.         published by the Free Software Foundation."; P();
  539.  
  540.         I(); "This program is distributed in the hope that it 
  541.         will be useful, but WITHOUT ANY WARRANTY; without 
  542.         even the implied warranty of MERCHANTABILITY or 
  543.         FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
  544.         General Public License for more details."; P();
  545.  
  546.         I(); "You should have received a copy of the GNU 
  547.         General Public License along with this program; if 
  548.         not, write to the Free Software Foundation, Inc., 675 
  549.         Mass Ave, Cambridge, MA 02139, USA."; P();
  550.  
  551.         I(); "ADVENTIONS distributes this game, but you are 
  552.         free to do what you will with it, provided you adhere 
  553.         to the terms in the GNU Public License v2. Send 
  554.         correspondence regarding this game or other works 
  555.         distributed by ADVENTIONS to"; P();
  556.  
  557.         "\tADVENTIONS\n
  558.          \tPO Box 851\n
  559.          \tColumbia, MD 21044"; P();
  560.  
  561.         I(); "If you want to report a bug or typo, be sure to 
  562.         include the version number of the copy you are 
  563.         playing, as well as the configuration of the machine 
  564.         you are running it on."; P();
  565.  
  566.         I(); "ADVENTIONS has many other games like this 
  567.         available, including adventures in the popular 
  568.         Unnkulian saga.  Send a self-addressed, stamped 
  569.         envelope to the address above for a current catalog 
  570.         of our releases, or drop us email online:\b
  571.  
  572.         \tCompuserve:\t76440,2671\n
  573.         \tGEnie:\t\tADVENTIONS\n
  574.         \tInternet:\tdmb@ai.mit.edu\b
  575.  
  576.         or on the following BBS's:\b
  577.  
  578.         \tFANTAZIA (410) 521-5636 (8N1)\n
  579.         \tHigh Energy BBS (415) 493-2420 (8N1)"; P();
  580.  
  581.         "***"; P();
  582.  
  583.         I(); "Most game companies have abandoned interactive 
  584.         fiction because it isn't profitable enough.  We think 
  585.         that interactive novels are exciting and important 
  586.         elements of the gaming world that offer possibilities 
  587.         currently impossible to explore in graphics-oriented 
  588.         settings.  We spend as much time on our games as 
  589.         \"normal\" authors spend on novels.  Please support 
  590.         us to help keep the interactive fiction genre alive.  
  591.         Thanks, and have fun!"; P();
  592.  
  593.         "*** NOTE: THIS IS A BETA-TEST VERSION ONLY! ***\n
  594.         Please do not distribute this version; it has been 
  595.         released for testing purposes only.  If you want to 
  596.         play this game, be sure to get the finished version; 
  597.         it should be available from wherever you got this 
  598.         copy."; P();
  599.  
  600.         "***";
  601.     }
  602. ;
  603.  
  604. /*
  605.  *   "Me" is the player's actor.  Pick up the default definition, basicMe,
  606.  *   from "adv.t".
  607.  */
  608. Me: basicMe
  609.     panicked = nil    // has the player panicked after closing time?
  610.     
  611.     // The original code only allowed the player to carry
  612.     // seven objects at a time.  Weight wasn't taken into
  613.     // consideration.
  614.  
  615.     maxbulk = 7
  616.  
  617.     //
  618.     // Give the player points for getting a fair ways into
  619.     // the cave.
  620.     //
  621.     awardedpointsforgettingfarin = nil
  622.     travelTo(room) = {
  623.         if (room = nil)
  624.             pass travelTo;
  625.         else if (global.closed and room.isoutside) {
  626.             "A mysterious recorded voice groans into life 
  627.             and announces, \"This exit is closed.  Please 
  628.             leave via main office.\"";
  629.  
  630.             if (not self.panicked) {
  631.                 self.panicked := true;
  632.  
  633.                 //
  634.                 // The player is obviously panicking
  635.                 // at closing time and is desperately
  636.                 // trying to get out.  In the original
  637.                 // code the endgame timer is (erroneously?)
  638.                 // set to 15 in this circumstance.
  639.                 //
  640.                 // Comments in the code suggest that the
  641.                 // intention was to *extend* the timer
  642.                 // by 15, so we'll do that here.
  643.                 //
  644.                 global.bonustime := global.bonustime +
  645.                     global.panictime;
  646.             }
  647.             
  648.             return;        // no pass travelTo
  649.         }
  650.         else if (not self.awardedpointsforgettingfarin) {
  651.             if (not room.notfarin) {
  652.                 incscore(global.farinpoints);
  653.                 self.awardedpointsforgettingfarin := true;
  654.             }
  655.         }
  656.  
  657.         pass travelTo;
  658.     }
  659. ;
  660.  
  661. /*
  662.  * darkTravel() is called whenever the player attempts to move from a dark
  663.  * location into another dark location.
  664.  *
  665.  * This isn't quite the way the original worked, but it's close enough.
  666.  */
  667. darkTravel: function
  668. {
  669.     "It is now pitch dark.  If you proceed you will likely fall 
  670.     into a pit."; 
  671.  
  672.     /*
  673.      * 1 in 4 chance of death.
  674.      */
  675.     if (rand(4) = 1) {
  676.         P(); I();
  677.         "You fell into a pit and broke every bone in your body!";
  678.         die();
  679.     }
  680. }
  681.